/*
 * CWowHeadItemImporter.java
 *
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 *
 * This file is part of JRogueDPS.
 *
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */
package geardatabase;

import geardatabase.CGemType.GemType;
import geardatabase.CItemQuality.ItemQuality;
import geardatabase.CItemSlot.ItemSlot;
import geardatabase.CItemType.ItemType;
import java.util.ArrayList;
import org.dom4j.Document;
import org.dom4j.Node;
import utility.CRemoteXML;

/**
 *
 * @author gmillward
 */
/*
<name><![CDATA[Valorous Bonescythe Helmet]]></name>
<level>213</level>
<quality id="4">Epic</quality>
<class id="4"><![CDATA[Armor]]></class>
<subclass id="2"><![CDATA[Leather Armor]]></subclass>
<icon displayId="55078">INV_Helmet_15</icon>
<inventorySlot id="1">Head</inventorySlot>
<htmlTooltip><![CDATA[<table><tr><td><b class="q4">Valorous Bonescythe Helmet</b><br />Binds when picked up<table width="100%"><tr><td>Head</td><th>Leather</th></tr></table>470 Armor<br />+69 Agility<br />+88 Stamina<!--e--><br /><span class="socket-meta q0">Meta Socket</span><br /><span class="socket-blue q0">Blue Socket</span><br /><span class="q0">Socket Bonus: +8 Agility</span><br />Durability 70 / 70<br />Classes: Rogue<br />Requires Level 80</td></tr></table><table><tr><td><span class="q2">Equip: Improves critical strike rating by 58&nbsp;<small>(<!--r80:32:58-->1.26%&nbsp;@&nbsp;L80)</small>.</span><br /><span class="q2">Equip: Increases your expertise rating by 42&nbsp;<small>(<!--r80:37:42-->5.12&nbsp;@&nbsp;L80)</small>.</span><br /><span class="q2">Equip: Increases attack power by 170.</span><br /><br /><span class="q">Valorous Bonescythe Battlegear (0/5)</span><div class="q0 indent"><span><!--si40495-->Valorous Bonescythe Breastplate</span><br /><span><!--si40496-->Valorous Bonescythe Gauntlets</span><br /><span><!--si40499-->Valorous Bonescythe Helmet</span><br /><span><!--si40500-->Valorous Bonescythe Legplates</span><br /><span><!--si40502-->Valorous Bonescythe Pauldrons</span></div><br /><span class="q0"><span>(2) Set: Increases the damage dealt by your Rupture by 10%.</span><br /><span>(4) Set: Reduces the Energy cost of your Combo Moves by 5%.</span></span></td></tr></table>]]></htmlTooltip>
<json><![CDATA[id:40499,name:'3Valorous Bonescythe Helmet',level:213,reqlevel:80,armor:470,slot:1,source:[5],sourcemore:[{t:1,ti:28992,n:'Valerie Langrom',z:4395}],classs:4,subclass:2]]></json>
<jsonEquip><![CDATA[slotbak:1,displayid:55078,reqlevel:80,classes:8,armor:470,itemset:-31,socket1:1,socket2:8,socketbonus:3313,atkpwr:170,critstrkrtng:58,exprtng:42,agi:69,sta:88,dura:70,nsockets:2]]></jsonEquip>
<link>http://www.wowhead.com/?item=40499</link>
 */
public class CWowHeadItemImporter {

    final private String c_wowHeadUrl = "www.wowhead.com";

    public CItem getWowHeadItem(int p_itemId) {
        return getWowHeadItem("http://" + c_wowHeadUrl + "/?item=" + p_itemId);
    }
    public CItem getWowHeadItem(String p_url) {

        String [] l_temp = null;
        l_temp = p_url.split("=");

        int l_itemId = Integer.parseInt(l_temp[1]);

        p_url += "&xml";
        CRemoteXML l_getXML = new CRemoteXML();
        Document l_itemDoc = l_getXML.extractData(p_url);
        if (l_itemDoc == null) {
            System.out.println("Failed to get " + p_url);
            return null;
        }

        CItem l_gearItem = new CItem(l_itemId);

        Node node = l_itemDoc.selectSingleNode("//wowhead/item");
        l_gearItem.setName(node.valueOf("name"));
        l_gearItem.setILevel(Integer.parseInt(node.valueOf("level")));
        l_gearItem.setGearQuality(this.getGearQuality(Integer.parseInt(getElementAttribute(l_itemDoc, "quality", "id"))));

        
        String l_imageName = node.valueOf("icon");
        String l_subClassID = getElementAttribute(l_itemDoc, "subclass", "id");
        String l_itemType = getElementAttribute(l_itemDoc, "class", "id") + ":" + l_subClassID;

        String l_itemSlotString = getElementAttribute(l_itemDoc, "inventorySlot", "id");
        if (!l_itemSlotString.equals("0")) {
            l_gearItem.setItemSlot(getItemSlot(l_itemSlotString));
            if (l_gearItem.getItemSlot() == ItemSlot.UNKNOWN) {
                System.out.println("Bad Inventory slot " + l_itemSlotString + " for [" + l_itemId + "] [" + l_gearItem.getName() + "]");
                return null;
            }
        } else
        {
            // Fudge in a GEM/Enchant or Poison as being UNKNOWN
            l_gearItem.setItemSlot(ItemSlot.UNKNOWN);
        }

        l_gearItem.setHtmlTooltip(node.valueOf("htmlTooltip"));
        String l_statsString = node.valueOf("jsonEquip");

        ItemSlot l_itemSlot = l_gearItem.getItemSlot();
        if (l_itemSlot == ItemSlot.TRINKET) {
            l_gearItem.setItemType(ItemType.TRINKET);
        } else if (l_itemSlot == ItemSlot.FINGER) {
            l_gearItem.setItemType(ItemType.RING);
        } else if (l_itemSlot == ItemSlot.UNKNOWN) {
            // Some sort of Gem
            l_gearItem.setItemType(ItemType.GEM);
        } else {
            l_gearItem.setItemType(getItemType(l_itemType));
            if (l_gearItem.getItemType() == ItemType.UNKNOWN) {
                System.out.println("Unknown item type for [" + l_itemId + "] [" + l_gearItem.getName() + "]");
                return null;
            }
        }

        if (l_gearItem.getItemType() == ItemType.GEM) {
            l_gearItem.setGemType(this.getGemType(Integer.parseInt(l_subClassID)));
        }

        ArrayList<CWowHeadKeyValue> l_json = splitWowHeadString(l_statsString);
        if (l_json != null) {
            for (int i = 0; i < l_json.size(); i++) {
                if (!addValuesToGear(l_json.get(i), l_gearItem)) {
                    l_gearItem.showData();
                    return null;
                }
            }
        }

        l_gearItem.showData();
        return l_gearItem;
    }

    private String getElementAttribute(Document p_doc, String p_element, String p_attribute) {
        Node l_node = p_doc.selectSingleNode("//wowhead/item/" + p_element);
        return l_node.valueOf("@" + p_attribute);
    }

    private boolean addValuesToGear(CWowHeadKeyValue p_keyValue, CItem p_gearItem) {
        String l_key = p_keyValue.key;
        String l_val = p_keyValue.value;

        if (l_key.equals("socket1")) {
            p_gearItem.addSocketHolder(getSocketType(l_val));
        } else if (l_key.equals("socket2")) {
            p_gearItem.addSocketHolder(getSocketType(l_val));
        } else if (l_key.equals("socket3")) {
            p_gearItem.addSocketHolder(getSocketType(l_val));
        } else if (l_key.equals("socket4")) {
            // You never know !!
            p_gearItem.addSocketHolder(getSocketType(l_val));
        } else if (l_key.equals("speed")) {
            p_gearItem.setWeaponSpeed(Double.parseDouble(l_val));
        } else if (l_key.equals("dmgmin1")) {
            p_gearItem.setMinWeaponDamage(Double.parseDouble(l_val));
        } else if (l_key.equals("dmgmax1")) {
            p_gearItem.setMaxWeaponDamage(Double.parseDouble(l_val));
        } else if (l_key.equals("agi")) {
            p_gearItem.getItemStats().addAgility(Integer.parseInt(l_val));
        } else if (l_key.equals("sta")) {
            p_gearItem.getItemStats().addStamina(Integer.parseInt(l_val));
        } else if (l_key.equals("hastertng")) {
            p_gearItem.getItemStats().addHasteRating(Integer.parseInt(l_val));
        } else if (l_key.equals("mlehastertng")) {
            p_gearItem.getItemStats().addHasteRating(Integer.parseInt(l_val));
        } else if (l_key.equals("rgdhastertng")) {
            p_gearItem.getItemStats().addHasteRating(Integer.parseInt(l_val));
        } else if (l_key.equals("splhastertng")) {
            p_gearItem.getItemStats().addHasteRating(Integer.parseInt(l_val));
        } else if (l_key.equals("critstrkrtng")) {
            p_gearItem.getItemStats().addCritRating(Integer.parseInt(l_val));
        } else if (l_key.equals("mlecritstrkrtng")) {
            p_gearItem.getItemStats().addCritRating(Integer.parseInt(l_val));
        } else if (l_key.equals("rgdcritstrkrtng")) {
            p_gearItem.getItemStats().addCritRating(Integer.parseInt(l_val));
        } else if (l_key.equals("splcritstrkrtng")) {
            p_gearItem.getItemStats().addCritRating(Integer.parseInt(l_val));
        } else if (l_key.equals("hitrtng")) {
            p_gearItem.getItemStats().addHitRating(Integer.parseInt(l_val));
        } else if (l_key.equals("mlehitrtng")) {
            p_gearItem.getItemStats().addHitRating(Integer.parseInt(l_val));
        } else if (l_key.equals("rgdhitrtng")) {
            p_gearItem.getItemStats().addHitRating(Integer.parseInt(l_val));
        } else if (l_key.equals("splhitrtng")) {
            p_gearItem.getItemStats().addHitRating(Integer.parseInt(l_val));
        } else if (l_key.equals("atkpwr")) {
            p_gearItem.getItemStats().addAttackPower(Integer.parseInt(l_val));
        } else if (l_key.equals("mleatkpwr")) {
            p_gearItem.getItemStats().addAttackPower(Integer.parseInt(l_val));
        } else if (l_key.equals("exprtng")) {
            p_gearItem.getItemStats().addExpertiseRating(Integer.parseInt(l_val));
        } else if (l_key.equals("socketbonus")) {
            setSocketBonusStats(p_gearItem.getItemBonusStats(), l_val);
        } else if (l_key.equals("armorpen")) {
            p_gearItem.getItemStats().addArmorPenRating(Integer.parseInt(l_val));
        } else if (l_key.equals("armorpenrtng")) {
            p_gearItem.getItemStats().addArmorPenRating(Integer.parseInt(l_val));
        }   else if (l_key.equals("str")) {
            p_gearItem.getItemStats().addStrength(Integer.parseInt(l_val));
        } else if (l_key.equals("healthrgn")) {
            return true;
        } else if (l_key.equals("manargn")) {
            return true;
        } else if (l_key.equals("int")) {
            return true;
        } else if (l_key.equals("splhastertng")) {
            return true;
        } else if (l_key.equals("splpwr")) {
            return true;
        } else if (l_key.equals("splheal")) {
            return true;
        } else if (l_key.equals("spldmg")) {
            return true;
        } else if (l_key.equals("block")) {
            return true;
        } else if (l_key.equals("splpen")) {
            return true;
        } else if (l_key.equals("mana")) {
            return true;
        } else if (l_key.equals("frospldmg")) {
            return true;
        } else if (l_key.equals("shaspldmg")) {
            return true;
        } else if (l_key.equals("firspldmg")) {
            return true;
        } else if (l_key.equals("arcspldmg")) {
            return true;
        }

        return true;
    }

    private ItemQuality getGearQuality(int p_quality)
    {
        switch (p_quality)
        {
            case 1: return ItemQuality.COMMON;
            case 2: return ItemQuality.UNCOMMON;
            case 3: return ItemQuality.RARE;
            case 4: return ItemQuality.EPIC;
            case 5: return ItemQuality.LEGENDARY;
            default : break;
        }

        return ItemQuality.UNKNOWN;
    }
    private GemType getGemType(int p_subType) {
        switch (p_subType) {
            case 0:
                return GemType.RED;
            case 1:
                return GemType.BLUE;
            case 2:
                return GemType.YELLOW;
            case 3:
                return GemType.PURPLE;
            case 4:
                return GemType.GREEN;
            case 5:
                return GemType.ORANGE;
            case 6:
                return GemType.META;
            case 8:
                return GemType.PRISMATIC;

            default:
                break;
        }
        return GemType.UNKNOWN;
    }

    private ItemSlot getItemSlot(String p_value) {
        int l_itemSlot = Integer.parseInt(p_value);

        switch (l_itemSlot) {
            case 1:
                return ItemSlot.HEAD;
            case 2:
                return ItemSlot.NECK;
            case 3:
                return ItemSlot.SHOULDERS;
            case 16:
                return ItemSlot.BACK;
            case 5:
            case 20:
                return ItemSlot.CHEST;
            case 9:
                return ItemSlot.WRIST;
            case 10:
                return ItemSlot.HANDS;
            case 6:
                return ItemSlot.WAIST;
            case 7:
                return ItemSlot.LEGS;
            case 8:
                return ItemSlot.FEET;
            case 11:
                return ItemSlot.FINGER;
            case 12:
                return ItemSlot.TRINKET;
            case 13:
                return ItemSlot.ONEHAND;
            case 21:
                return ItemSlot.MAINHAND;
            case 14:
            case 22:
            case 23:
                return ItemSlot.OFFHAND;
            case 15:
            case 25:
                return ItemSlot.RANGED;
            default:
                return ItemSlot.UNKNOWN;
        }
    }

    private ItemType getItemType(String p_value) {
        if (p_value.equals("4:2")) {
            return ItemType.LEATHER;
        } else if (p_value.equals("2:15")) {
            return ItemType.DAGGER;
        } else if (p_value.equals("2:13")) {
            return ItemType.FIST;
        } else if (p_value.equals("2:4")) {
            return ItemType.MACE;
        } else if (p_value.equals("2:0")) {
            return ItemType.AXE;
        } else if (p_value.equals("2:7")) {
            return ItemType.SWORD;
        } else if (p_value.equals("2:2")) {
            return ItemType.BOW;
        } else if (p_value.equals("2:18")) {
            return ItemType.CROSSBOW;
        } else if (p_value.equals("2:3")) {
            return ItemType.GUN;
        } else if (p_value.equals("2:16")) {
            return ItemType.THROWN;
        } else if (p_value.equals("4:-6")) {
            return ItemType.CLOAK;
        } else if (p_value.equals("4:-3")) {
            return ItemType.AMULET;
        } else {
            return ItemType.UNKNOWN;
        }

    }

    private GemType getSocketType(String p_value) {
        int l_gemType = Integer.parseInt(p_value);
        switch (l_gemType) {
            case 1:
                return GemType.META;
            case 2:
                return GemType.RED;
            case 4:
                return GemType.YELLOW;
            case 6:
                return GemType.ORANGE;
            case 8:
                return GemType.BLUE;
            case 10:
                return GemType.PURPLE;
            case 12:
                return GemType.GREEN;
            case 14:
                return GemType.PRISMATIC;
            default:
                return GemType.UNKNOWN;
        }
    }

    private void setSocketBonusStats(CStats p_stats, String p_val) {
        int l_val = Integer.parseInt(p_val);
        switch (l_val) {
            case 2771:
                p_stats.addCritRating(8);
                break;
            case 2787:
                p_stats.addCritRating(8);
                break;
            case 2843:
                p_stats.addCritRating(8);
                break;
            case 2864:
                p_stats.addCritRating(4);
                break;
            case 2868:
                p_stats.addStamina(6);
                break;
            case 2873:
                p_stats.addHitRating(4);
                break;
            case 2874:
                p_stats.addCritRating(4);
                break;
            case 2877:
                p_stats.addAgility(4);
                break;
            case 2882:
                p_stats.addStamina(6);
                break;
            case 2892:
                p_stats.addStrength(4);
                break;
            case 2895:
                p_stats.addStamina(4);
                break;
            case 2908:
                p_stats.addCritRating(6);
                break;
            case 2927:
                p_stats.addStrength(4);
                break;
            case 2936:
                p_stats.addAttackPower(8);
                break;
            case 2951:
                p_stats.addCritRating(4);
                break;
            case 2952:
                p_stats.addCritRating(4);
                break;
            case 2963:
                p_stats.addHasteRating(8);
                break;
            case 3094:
                p_stats.addExpertiseRating(4);
                break;
            case 3204:
                p_stats.addCritRating(3);
                break;
            case 3263:
                p_stats.addCritRating(4);
                break;
            case 3267:
                p_stats.addHasteRating(4);
                break;
            case 3301:
                p_stats.addCritRating(6);
                break;
            case 3303:
                p_stats.addHasteRating(8);
                break;
            case 3305:
                p_stats.addStamina(12);
                break;
            case 3307:
                p_stats.addStamina(9);
                break;
            case 3308:
                p_stats.addHasteRating(4);
                break;
            case 3309:
                p_stats.addHasteRating(6);
                break;
            case 3312:
                p_stats.addStrength(8);
                break;
            case 3313:
                p_stats.addAgility(8);
                break;
            case 3314:
                p_stats.addCritRating(8);
                break;
            case 3316:
                p_stats.addCritRating(6);
                break;
            case 3351:
                p_stats.addHitRating(6);
                break;
            case 3354:
                p_stats.addStamina(12);
                break;
            case 3355:
                p_stats.addAgility(6);
                break;
            case 3356:
                p_stats.addAttackPower(12);
                break;
            case 3357:
                p_stats.addStrength(6);
                break;
            case 3362:
                p_stats.addExpertiseRating(6);
                break;
            case 3764:
                p_stats.addAttackPower(12);
                break;
            case 3765:
                p_stats.addArmorPenRating(4);
                break;
            case 3766:
                p_stats.addStamina(12);
                break;
            case 3778:
                p_stats.addExpertiseRating(8);
                break;
            default:
                break;
        }
    }

    private ArrayList<CWowHeadKeyValue> splitWowHeadString(String p_string) {
        // WowHead jsonEqip strings look kinda like this
        // slotbak:1,displayid:55078,reqlevel:80,classes:8,armor:470,itemset:-31,socket1:1,socket2:8,socketbonus:3313,atkpwr:170,critstrkrtng:58,exprtng:42,agi:69,sta:88,dura:70,nsockets:2
        //
        // So split using delimiter ',' then generate key/value for each split string.

        if (p_string == null) {
            return null;
        }

        ArrayList<CWowHeadKeyValue> l_arrayList = new ArrayList<CWowHeadKeyValue>();
        String l_splitString[] = p_string.split(",");

        for (int i = 0; i < l_splitString.length; i++) {
            // Split each string into key/value
            String l_keyValue[] = l_splitString[i].split(":");
            l_keyValue[1].replaceAll("'", "");

            l_arrayList.add(new CWowHeadKeyValue(l_keyValue[0], l_keyValue[1]));
        }

        return l_arrayList;
    }
}
